#pragma once

#include <iostream>
#include <queue>
#include <mutex>
#include <unistd.h>
#include <pthread.h>
#include "lockGuard.hpp"

const int gDEFAULT_CAP = 5;

template<class T>
class BlockQueue
{
private:
    bool isQueueEmpty()
    {
        return bq_.size() == 0;
    }

    bool isQueueFull()
    {
        return bq_.size() == capacity_;
    }
public:
    BlockQueue(int capacity = gDEFAULT_CAP)
        :capacity_(capacity)
    {
        pthread_mutex_init(&mtx_, nullptr);
        pthread_cond_init(&Empty_, nullptr);
        pthread_cond_init(&Full_, nullptr);
    }

    void push(const T& in)  // 生产者
    {
        // pthread_mutex_lock(&mtx_);
        // // 1.先检测当前的临界资源是否能够满足访问条件
        // // 我还在临界区中，我是锁的持有者，锁得释放啊？
        // // pthread_cond_wait第二个参数是一把锁，输入这把锁，挂起等待时，这把锁会自动释放
        // // 当我被唤醒时，我从哪里醒来呢？       从哪里挂起，从哪里唤醒, 被唤醒的时候，我们还在临界区中被唤醒
        // // 当我们被唤醒的时候，pthread_cond_wait,会自动帮我们线程获取锁
        // // pthread_cond_wait:只要是一个函数，有可能失败
        // // pthread_cond_wait：可能存在 伪唤醒 的情况    把if换成while
        // while (isQueueFull()) pthread_cond_wait(&Full_, &mtx_);
        // // 2.访问临界资源  100%确定，资源是就绪的!
        // bq_.push(in);
        // //if (bq_.size() >= capacity_ / 2) pthread_cond_signal(&Empty_);
        // pthread_cond_signal(&Empty_);
        // pthread_mutex_unlock(&mtx_);


        lockGuard lockguard(&mtx_); // 自动调用构造函数
        while (isQueueFull()) 
            pthread_cond_wait(&Full_, &mtx_);
        // 2.访问临界资源  100%确定，资源是就绪的!
        bq_.push(in);
        pthread_cond_signal(&Empty_);
    }// 自动调用lockguard析构函数

    void pop(T* out)
    {
        // pthread_mutex_lock(&mtx_);
        // while (isQueueEmpty()) pthread_cond_wait(&Empty_, &mtx_);
        // *out = bq_.front();
        // bq_.pop();
        // pthread_cond_signal(&Full_);
        // pthread_mutex_unlock(&mtx_);


        lockGuard lockguard(&mtx_);
        while (isQueueEmpty()) 
            pthread_cond_wait(&Empty_, &mtx_);
        *out = bq_.front();
        bq_.pop();
        pthread_cond_signal(&Full_);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&mtx_);
        pthread_cond_destroy(&Empty_);
        pthread_cond_destroy(&Full_);
    }
private:
    std::queue<T> bq_; // 阻塞队列
    int capacity_; // 容量上限
    pthread_mutex_t mtx_; // 通过互斥锁，保护队列安全
    pthread_cond_t Empty_; // 条件变量, 用它表示阻塞队列，是否为空的条件
    pthread_cond_t Full_; // 条件变量，用它表示bq，是否满了的条件
};
